package chap_02_CAS.step_02_Atomic;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description 基本数据类型的原子类
 * @Author shihan
 * @Date 2022/10/30 11:37
 * @Version 1.0
 */
public class Atomic_01_BasicType {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    // 因为创建了50个线程，所以初始化值是50
    private CountDownLatch countDownLatch = new CountDownLatch(50);

    public void increment() {
        atomicInteger.incrementAndGet();
    }

    public static void main(String[] args) {
        //originWithSleep();
        originWithCountDownLatch();
    }

    /**
     * 不是很优雅的使用 sleep 的方式阻塞
     */
    private static void originWithSleep() {
        Atomic_01_BasicType basicType = new Atomic_01_BasicType();

        for (int i = 0; i < 50; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    basicType.increment();
                }
            }, String.valueOf(i)).start();
        }

        // 延迟两秒钟，让上面的五十个线程执行结束，然后在主线程打印计算结果
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(basicType.atomicInteger);
    }

    /**
     * 优雅地使用 CountDownLatch 的方式进行阻塞
     * PS：现在先建立一个认知和思想，什么时候能够用 CountDownLatch
     * TODO CountDownLatch 底层原理
     */
    private static void originWithCountDownLatch() {
        Atomic_01_BasicType basicType = new Atomic_01_BasicType();

        for (int i = 0; i < 50; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    basicType.increment();
                }
                // 每执行完毕一个线程，将门栓计数减一
                basicType.countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }

        // 用 countDownLatch 来进行阻塞，只要50个线程执行结束了，就立即放开阻塞，让主线程执行
        try {
            // 判断当前门栓计数是否为零，不为零则阻塞，为零则放开阻塞继续执行
            basicType.countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(basicType.atomicInteger);
    }

}
